﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Management;

namespace MyPhotoIndex.Utilities.WindowsManagement
{
    public class RemovableDevices
    {
        private static ManagementEventWatcher m_insertWatcher = null;
        private static ManagementEventWatcher m_removeWatcher = null;
        private static ManagementEventWatcher m_CDinsertWatcher = null;
        private static ManagementEventWatcher m_networkWatcher = null;

        private static EventHandler<DeviceNotifictionEventArgs> m_deviceInsertEvent;
        private static EventHandler<DeviceNotifictionEventArgs> m_deviceRemovedEvent;

        private static EventHandler<DeviceNotifictionEventArgs> m_CDInsertEvent;
        private static EventHandler<DeviceNotifictionEventArgs> m_CDRemovedEvent;

        private static EventHandler<DeviceNotifictionEventArgs> m_networkStatusEvent;

        public static event EventHandler<DeviceNotifictionEventArgs> DeviceInsertEvent
        {
            add
            {
                Init();
                m_deviceInsertEvent += value;
            }

            remove
            {
                m_deviceInsertEvent -= value;
            }

        }
        public static event EventHandler<DeviceNotifictionEventArgs> DeviceRemovedEvent
        {
            add
            {
                Init();
                m_deviceRemovedEvent += value;
            }

            remove
            {
                m_deviceRemovedEvent -= value;
            }

        }

        public static event EventHandler<DeviceNotifictionEventArgs> CDInsertEvent
        {
            add
            {
                Init();
                m_CDInsertEvent += value;
            }

            remove
            {
                m_CDInsertEvent -= value;
            }

        }
        public static event EventHandler<DeviceNotifictionEventArgs> CDRemovedEvent
        {
            add
            {
                Init();
                m_CDRemovedEvent += value;
            }

            remove
            {
                m_CDRemovedEvent -= value;
            }

        }

        public static event EventHandler<DeviceNotifictionEventArgs> NetworkStatusEvent
        {
            add
            {
                Init();
                m_networkStatusEvent += value;
            }

            remove
            {
                m_networkStatusEvent -= value;
            }
        }

        private static RemovableDevices m_cleanerInstance;

        private RemovableDevices()
        {
        }

        ~RemovableDevices()
        {
            Quit();
        }

        private static void Quit()
        {//TODO: we should reely avoid this.. will kill all new events for the application
            if (m_insertWatcher != null)
            {
                m_insertWatcher.Stop();
                m_insertWatcher.Dispose();
            }

            if (m_removeWatcher != null)
            {
                m_removeWatcher.Stop();
                m_removeWatcher.Dispose();
            }

            if (m_CDinsertWatcher != null)
            {
                m_CDinsertWatcher.Stop();
                m_CDinsertWatcher.Dispose();
            }
        }

        private static void Init()
        {
            if (m_insertWatcher != null)
            {
                return;
            }

            m_cleanerInstance = new RemovableDevices();

            ManagementScope scope = new ManagementScope();
            scope.Options.EnablePrivileges = false;

            try
            {
                WqlEventQuery query = new WqlEventQuery();
                query.EventClassName = "__InstanceCreationEvent";
                query.WithinInterval = new TimeSpan(0, 0, 5);
                query.Condition = @"TargetInstance ISA 'Win32_USBControllerdevice'";
                m_insertWatcher = new ManagementEventWatcher(scope, query);
                m_insertWatcher.EventArrived += new EventArrivedEventHandler(m_watcher_USBInsert);
                m_insertWatcher.Start();

                query = new WqlEventQuery();
                query.EventClassName = "__InstanceDeletionEvent";
                query.WithinInterval = new TimeSpan(0, 0, 5);
                query.Condition = @"TargetInstance ISA 'Win32_USBControllerdevice'";
                m_removeWatcher = new ManagementEventWatcher(scope, query);
                m_removeWatcher.EventArrived += new EventArrivedEventHandler(m_watcher_USBRemoved);
                m_removeWatcher.Start();

                query = new WqlEventQuery();
                query.EventClassName = "__InstanceModificationEvent";
                query.WithinInterval = new TimeSpan(0, 0, 5);
                query.Condition = @"TargetInstance ISA 'Win32_CDROMDrive' AND PreviousInstance.MediaLoaded<>TargetInstance.MediaLoaded";
                m_CDinsertWatcher = new ManagementEventWatcher(query);
                m_CDinsertWatcher.EventArrived += new EventArrivedEventHandler(m_watcher_CDNotification);
                m_CDinsertWatcher.Start();

                query = new WqlEventQuery();
                query.EventClassName = "__InstanceModificationEvent";
                query.WithinInterval = new TimeSpan(0, 0, 5);
                query.Condition = @"PreviousInstance ISA 'Win32_NetworkConnection'";
                m_networkWatcher = new ManagementEventWatcher(query);
                m_networkWatcher.EventArrived += new EventArrivedEventHandler(m_watcher_NetworkNotification);
                m_networkWatcher.Start();
            }
            catch (Exception e)
            {
                Logger.Log(e);

                if (m_insertWatcher != null)
                {
                    m_insertWatcher.Stop();
                }
            }
        }

        private static void m_watcher_USBInsert(object sender, EventArrivedEventArgs e)
        {//TODO: Get Inserted drive letter...
            if (m_deviceInsertEvent != null)
            {
                m_deviceInsertEvent.Invoke(sender, new DeviceNotifictionEventArgs());
            }
        }

        private static void m_watcher_USBRemoved(object sender, EventArrivedEventArgs e)
        {//TODO: Get Inserted drive letter...
            if (m_deviceRemovedEvent != null)
            {
                m_deviceRemovedEvent.Invoke(sender, new DeviceNotifictionEventArgs());
            }
        }

        private static void m_watcher_CDNotification(object sender, EventArrivedEventArgs e)
        {//TODO: Get Inserted drive letter...
            using (ManagementBaseObject targetInstanceObject = e.NewEvent["TargetInstance"] as ManagementBaseObject)
            {
                if (true == (bool)targetInstanceObject["MediaLoaded"])
                {
                    if (m_CDInsertEvent != null)
                    {
                        m_CDInsertEvent.Invoke(sender, new DeviceNotifictionEventArgs());
                    }
                }
                else
                {
                    if (m_CDRemovedEvent != null)
                    {
                        m_CDRemovedEvent.Invoke(sender, new DeviceNotifictionEventArgs());
                    }
                }
            }
        }

        private static void m_watcher_NetworkNotification(object sender, EventArrivedEventArgs e)
        {
            if (m_networkStatusEvent != null)
            {
                m_networkStatusEvent.Invoke(sender, new DeviceNotifictionEventArgs());
            }
        }
    }
}
